home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / stik_dev / smtp / smtp.c
C/C++ Source or Header  |  1995-10-01  |  11KB  |  519 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5.  
  6. #include <tos.h>
  7.  
  8. #include "\include\drivers.h"
  9. #include "\include\transprt.h"
  10.  
  11. #define CON 2
  12.  
  13. /* These definitions are necessary.  transprt.h has external
  14.  * declarations for them.
  15.  */
  16. DRV_LIST *drivers = (DRV_LIST *)NULL;
  17. TPL *tpl = (TPL *)NULL;
  18.  
  19. static long msglist[100];
  20. static int16 nextmsg = 0, endmsg = 0;
  21. static char mailpath[50];
  22.  
  23. static void strip_crlf(char *s)
  24. {
  25.     register int16 len = (int16)strlen(s);
  26.  
  27.     s = s + len;
  28.  
  29.     while (len > 0 && *s == '\0' || *s == '\r' || *s == '\n') {
  30.         len -= 1;
  31.         s -= 1;
  32.     }
  33.     s[1] = '\0';
  34. }
  35.  
  36. static int16 get_response(int16 cn, int16 t)
  37. {
  38.     int16 response, count, c, i = 0;
  39.     char s[100], sr[4];
  40.     clock_t to = clock() + (clock_t)t * CLK_TCK;
  41.  
  42.     while (TRUE) {
  43.         count = CNbyte_count(cn);
  44.         if (count < 0)
  45.             return (count);
  46.  
  47.         if (to < clock())
  48.             return (E_USERTIMEOUT);
  49.  
  50.         if (Bconstat(CON)) {
  51.             Bconin(CON);
  52.             return (E_USERTIMEOUT);
  53.         }
  54.  
  55.         else while (count > 0) {
  56.             count -= 1;
  57.             c = CNget_char(cn);
  58.             if (c < E_NODATA)
  59.                 return (c);
  60.             s[i++] = (char)c;
  61.  
  62.             if (c == '\r')
  63.                 s[i-1] = '\0';
  64.  
  65.             else if (c == '\n') {
  66.                 s[i-1] = '\0';
  67.                 strncpy(sr, s, 3);
  68.                 sr[3] = '\0';
  69.                 response = atoi(sr);
  70.                 Cconws(s);
  71.                 Cconws("\r\n");
  72.                 return(response);
  73.             }
  74.         }
  75.     }
  76. }
  77.  
  78. static int16 send_msg(int16 cn, int16 t, int16 msgi)
  79. {
  80.     int16 rc, tstat;
  81.     FILE *fp;
  82.     char fname[100], wname[100];
  83.     char line[500];     /* That's a bloody long line of text..  */
  84.     char cline[50];
  85.     char lts[20];
  86.  
  87.     strcpy(wname, mailpath);
  88.     strcat(wname, ltoa(msglist[msgi], lts, 10));
  89.     strcat(wname, ".wrk");
  90.  
  91.     ser_disable();
  92.     if ((fp = fopen(wname, "rb")) == (FILE *)NULL) {
  93.         Cconws("Can't open ");
  94.         Cconws(fname);
  95.         Cconws("\r\n");
  96.         ser_enable();
  97.         return (-1);
  98.     }
  99.  
  100.     fgets(line, 500, fp);
  101.  
  102.     if (fgets(line, 500, fp) == (char *)NULL) {
  103.         Cconws("Bad work file, line 2: ");
  104.         Cconws(fname);
  105.         Cconws("\r\n");
  106.         fclose(fp);
  107.         ser_enable();
  108.         return (-1);
  109.     }
  110.     ser_enable();
  111.  
  112.     strip_crlf(line);
  113.  
  114.     strcpy(cline, "MAIL FROM:<");
  115.     strcat(cline, line);
  116.     strcat(cline, ">\r\n");
  117.  
  118.     TCP_send(cn, cline, (int16)strlen(cline));
  119.  
  120.     if (get_response(cn, t) != 250) {
  121.         Cconws("Can't mail message\r\n");
  122.         return(-1);
  123.     }
  124.  
  125.     ser_disable();
  126.     if (fgets(line, 500, fp) == (char *)NULL) {
  127.         Cconws("Bad work file, line 3: ");
  128.         Cconws(fname);
  129.         Cconws("\r\n");
  130.         fclose(fp);
  131.         ser_enable();
  132.         return (-1);
  133.     }
  134.     fclose(fp);        /* Finished with .wrk file    */
  135.     ser_enable();
  136.  
  137.     strip_crlf(line);
  138.  
  139.     strcpy(cline, "RCPT TO:<");
  140.     strcat(cline, line);
  141.     strcat(cline, ">\r\n");
  142.  
  143.     TCP_send(cn, cline, (int16)strlen(cline));
  144.  
  145.     rc = get_response(cn, t);
  146.     if (rc != 250 && rc != 251) {
  147.         Cconws("Can't mail message\r\n");
  148.         return(-1);
  149.     }
  150.  
  151.     strcpy(fname, mailpath);
  152.     strcat(fname, ltoa(msglist[(long)msgi], lts, 10));
  153.     strcat(fname, ".txt");
  154.  
  155.     ser_disable();
  156.     if ((fp = fopen(fname, "r")) == (FILE *)NULL) {
  157.         Cconws("Can't open ");
  158.         Cconws(fname);
  159.         Cconws("\r\n");
  160.         ser_enable();
  161.         return (-1);
  162.     }
  163.     ser_enable();
  164.  
  165.     TCP_send(cn, "DATA\r\n", 6);
  166.     if (get_response(cn, t) != 354) {
  167.         Cconws("Can't mail message\r\n");
  168.         ser_disable();
  169.         fclose(fp);
  170.         ser_enable();
  171.         return(-1);
  172.     }
  173.  
  174.     ser_disable();
  175.     while ((fgets(line, 500, fp) != (char *)NULL) && (line[0] != '\0')) {
  176.         strip_crlf(line);
  177.         strcat(line, "\r\n");
  178.  
  179.         ser_enable();
  180.  
  181.         if (line[0] == '.' && line[1] == '\r' && line[2] == '\n') {
  182.             do {
  183.                 tstat = TCP_send(cn, "..\r\n", 4);
  184.                 if (Bconstat(CON) && ((Bconin(CON) & 0xff) == '\033')) {
  185.                     tstat = E_USERTIMEOUT;
  186.                     break;
  187.                 }
  188.             } while (tstat == E_OBUFFULL);
  189.         }
  190.         else {
  191.             do {
  192.                 tstat = TCP_send(cn, line, (int16)strlen(line));
  193.                 if (Bconstat(CON) && ((Bconin(CON) & 0xff) == '\033')) {
  194.                     tstat = E_USERTIMEOUT;
  195.                     break;
  196.                 }
  197.             } while (tstat == E_OBUFFULL);
  198.  
  199.         }
  200.         if (tstat != E_NORMAL)
  201.             break;
  202.         ser_disable();
  203.     }
  204.     ser_disable();
  205.     fclose(fp);
  206.     ser_enable();
  207.  
  208.     if (tstat != E_NORMAL) {
  209.         Cconws("Error sending message\r\n");
  210.         return(-1);
  211.     }
  212.  
  213.     TCP_send(cn, ".\r\n", 3);
  214.     if (get_response(cn, t) != 250) {
  215.         Cconws("Error sending message\r\n");
  216.         return(-1);
  217.     }
  218.  
  219.     /* After a 250 response it should be cool to to delete the message  */
  220.  
  221.     ser_disable();
  222.     Fdelete(fname);
  223.     Fdelete(wname);
  224.     ser_enable();
  225.  
  226.     return (0); /* Message sent OK ! */
  227. }
  228.  
  229. static int16 get_first_msg(void)
  230. {
  231.     int16 len, fstat;
  232.     long msg, lastseq;
  233.     char fname[100];
  234.     char aln[20], *ptr;
  235.     FILE *fp;
  236.     DTA *saved, dta;
  237.  
  238.     ptr = getvstr("SMTP_MAILPATH");
  239.     if (ptr[1] == '\0' && (ptr[0] == '0' || ptr[0] == '1')) {
  240.         Cconws("smtp(): SMTP_MAILPATH not set\r\n");
  241.         return (-1);
  242.     }
  243.     strcpy(mailpath, ptr);
  244.  
  245.     len = (int16)strlen(mailpath);
  246.     if (mailpath[len-1] != '\\') {
  247.         mailpath[len++] = '\\';
  248.         mailpath[len] = '\0';
  249.     }
  250.  
  251.     strcpy(fname, mailpath);
  252.     strcat(fname, "sequence.seq");
  253.  
  254.     ser_disable();
  255.  
  256.     if ((fp = fopen(fname, "rb")) == (FILE *)NULL) {
  257.         Cconws("No sequence.seq file in spool\\mqueue\r\n");
  258.         return (-1);
  259.     }
  260.  
  261.     fgets(aln, 20, fp);
  262.     fclose(fp);
  263.     lastseq = atol(aln);
  264.  
  265.     if (lastseq == 0) {
  266.         Cconws("Empty sequence.seq file\r\n");
  267.         return (-1);
  268.     }
  269.  
  270.     saved = Fgetdta();
  271.     Fsetdta(&dta);
  272.  
  273.     strcpy(fname, mailpath);
  274.     strcat(fname, "*.wrk");
  275.  
  276.     fstat = Fsfirst(fname, 0);
  277.  
  278.     while (fstat == 0) {
  279.         msg = atol(dta.d_fname);
  280.  
  281.         if (msg <= lastseq) {
  282.             msglist[(long)endmsg] = msg;
  283.             endmsg++;
  284.             if (endmsg == 100)  /* Our batch limit  */
  285.                 break;
  286.         }
  287.  
  288.         fstat = Fsnext();
  289.     }
  290.     Fsetdta(saved);
  291.  
  292.     ser_enable();
  293.  
  294.     if (endmsg) {
  295.         nextmsg += 1;
  296.         return (nextmsg - 1);
  297.     }
  298.     else
  299.         return (-1);    /* No mail to send    */
  300. }
  301.  
  302. static int16 get_next_msg(void)
  303. {
  304.     if (nextmsg < endmsg) {
  305.         nextmsg += 1;
  306.         return (nextmsg - 1);
  307.     }
  308.     else
  309.         return (-1);
  310. }
  311.  
  312. static int16 helo_smtp(int16 cn, int16 t)
  313. {
  314.     char helo_msg[100], *ptr;
  315.  
  316.     ptr = getvstr("SMTP_HOSTNAME");
  317.     if (ptr[1] == '\0' && (ptr[0] == '0' || ptr[0] == '1')) {
  318.         ptr = getvstr("HOSTNAME");
  319.         if (ptr[1] == '\0' && (ptr[0] == '0' || ptr[0] == '1')) {
  320.             ptr = "no_host_name";
  321.         }
  322.     }
  323.     strcpy(helo_msg, "HELO ");
  324.     strcat(helo_msg, ptr);
  325.     strcat(helo_msg, "\r\n");
  326.  
  327.     TCP_send(cn, helo_msg, (int16)strlen(helo_msg));
  328.  
  329.     if (get_response(cn, t) != 250)
  330.         return (-1);    /* Fail */
  331.  
  332.     return (0);
  333. }
  334.  
  335. static int16 close_smtp(int16 cn, int16 t)
  336. {
  337.     int16 tstat;
  338.  
  339.     tstat = (int16)TCP_close(cn, t);
  340.     Cconws("TCP_close() returns: ");
  341.     Cconws(get_err_text(tstat));
  342.     Cconws("\r\n");
  343.  
  344.     return (tstat);
  345. }
  346.  
  347. static int16 quit_smtp(int16 cn, int16 t)
  348. {
  349.     TCP_send(cn, "QUIT\r\n", 6);
  350.  
  351.     if (get_response(cn, t) != 221)
  352.         return (-1);    /* Fail */
  353.  
  354.     return (0);
  355. }
  356.  
  357. static int16 connect_smtp(void)
  358. {
  359.     int16 cn, x;
  360.     char *ptr;
  361.     clock_t tout;
  362.     uint32 rhost;
  363.  
  364.     ptr = getvstr("SMTPSERVER");
  365.     if (ptr[1] == '\0' && (ptr[0] == '0' || ptr[0] == '1')) {
  366.         ptr = getvstr("PROVIDER");
  367.         if (ptr[1] == '\0' && (ptr[0] == '0' || ptr[0] == '1')) {
  368.             Cconws("pop(): SMTPSERVER/PROVIDER not set\r\n");
  369.             return (-1);
  370.         }
  371.     }
  372.  
  373.     x = resolve(ptr, (char **)NULL, &rhost, 1);
  374.     if (x < 0) {
  375.         Cconws(get_err_text(x));
  376.         Cconws("\r\n");
  377.         return (-1);
  378.     }
  379.  
  380.     if ((cn = TCP_open(rhost, 25, 0, 2000)) < 0) {
  381.         Cconws("TCP_open() returns ");
  382.         Cconws(get_err_text(cn));
  383.         Cconws("\r\n");
  384.         return (-1);
  385.     }
  386.     tout = clock() + (clock_t)1000;    /* 5 second delay    */
  387.     while (tout > clock()) {
  388.         if ((CNbyte_count(cn) > 0) && (get_response(cn, 60) != 220)) {
  389.             Cconws("Mail server not interested\r\n");
  390.             quit_smtp(cn, 10);
  391.             close_smtp(cn, 10);
  392.             return(-1);
  393.         }
  394.     }
  395.  
  396.     return (cn);
  397. }
  398.  
  399. /*  Now for the real version...
  400.  */
  401. void smtp(void)
  402. {
  403.     int16 cn, next_msg;
  404.  
  405.     nextmsg = endmsg = 0;
  406.  
  407.     if ((next_msg = get_first_msg()) < 0) {
  408.         Cconws("No messages to send\r\n");
  409.         return;
  410.     }
  411.     if ((cn = connect_smtp()) < 0) {
  412.         Cconws("Couldn't connect to mail host\r\n");
  413.         return;
  414.     }
  415.     if (helo_smtp(cn, 60) < 0) {
  416.         Cconws("Mail host not receiving\r\n");
  417.         quit_smtp(cn, 60);
  418.         close_smtp(cn, 10);
  419.  
  420.         return;
  421.     }
  422.     do {
  423.         if (send_msg(cn,300, next_msg) < 0) {
  424.             Cconws("Error sending message\r\n");
  425.             msglist[next_msg] = 0L;
  426.         }
  427.     } while ((next_msg = get_next_msg()) > 0);
  428.  
  429.     Cconws("Mail transactions complete\r\n");
  430.  
  431.     quit_smtp(cn, 30);
  432.     close_smtp(cn, 60);
  433. }
  434.  
  435. /* Function to wait for a keypress    */
  436.  
  437. static void pause(void)
  438. {
  439.     Cconws("Press any key to continue...\r\n"); /* Just like DOS :-)    */
  440.  
  441.     while (Bconstat(CON))
  442.         ;
  443.     Bconin(CON);
  444. }
  445.  
  446. /* Put 'STIK' cookie value into drivers */
  447.  
  448. typedef struct {
  449.     long cktag;
  450.     long ckvalue;
  451. } ck_entry;
  452.  
  453. static long init_drivers(void)
  454. {
  455.     long i = 0;
  456.     ck_entry *jar = *((ck_entry **) 0x5a0);
  457.  
  458.     while (jar[i].cktag) {
  459.         if (!strncmp((char *)&jar[i].cktag, CJTAG, 4)) {
  460.             drivers = (DRV_LIST *)jar[i].ckvalue;
  461.             return (0);
  462.         }
  463.         ++i;
  464.     }
  465.     return (0);    /* Pointless return value...    */
  466. }
  467. static int initialise(void)
  468. {
  469.     static long init_drivers(void);
  470.  
  471.     Supexec(init_drivers);
  472.  
  473.     /* See if we got a value    */
  474.  
  475.     if (drivers == (DRV_LIST *)NULL) {
  476.         Cconws("STiK is not loaded\r\n");
  477.         return (FALSE);
  478.     }
  479.  
  480.     /* Check Magic number    */
  481.  
  482.     if (strcmp(MAGIC, drivers->magic)) {
  483.         Cconws("Magic string doesn't match\r\n");
  484.         return (FALSE);
  485.     }
  486.  
  487.     /* OK, now we can get the address of the "TRANSPORT" layer
  488.      * driver.  If this seems unnecessarily complicated, it's
  489.      * because I tried to create today, what I would like to
  490.      * use later on.  In future, there will be multiple
  491.      * drivers accessible via this method.  With luck, your
  492.      * code will still work with future versions of my software.
  493.      */
  494.  
  495.     tpl = (TPL *)get_dftab(TRANSPORT_DRIVER);
  496.  
  497.     if (tpl == (TPL *)NULL) {
  498.         Cconws("Transport layer *not* loaded\r\n");
  499.         return (FALSE);
  500.     }
  501.     Cconws("Transport layer loaded, Author ");
  502.     Cconws(tpl->author);
  503.     Cconws(", version ");
  504.     Cconws(tpl->version);
  505.     Cconws("\r\n");
  506.  
  507.     return (TRUE);
  508. }
  509.  
  510. void main(void)
  511. {
  512.     Cconws("\033E");
  513.  
  514.     if (initialise())
  515.         smtp();
  516.  
  517.     pause();
  518. }
  519.